package com.mobileClientKernel.android.serviceManager.volley;


import com.android.volley.AuthFailureError;
import com.android.volley.Header;
import com.android.volley.Request;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.BaseHttpStack;
import com.android.volley.toolbox.HttpResponse;
import com.mobileClientKernel.android.commonLayer.JJLog;
import com.mobileClientKernel.android.serviceManager.network.requestexecutor.VolleyRequest;


import org.apache.http.HttpEntity;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;

import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class OkHttpStack extends BaseHttpStack {

    private static String LogModuleName = "OkHttpStack";

    private OkHttpClient mClient;

    public OkHttpStack(OkHttpClient client) {
        this.mClient = client;
    }

    public OkHttpStack() {
        this.mClient = new OkHttpClient();
    }


    @Override
    public com.android.volley.toolbox.HttpResponse executeRequest(final Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {

        //对上传图片请求 设置超时时间
        OkHttpClient.Builder clientBuilder = mClient.newBuilder();

        long connectTimeout = 30000;
        long readTimeout = 30000;
        long writeTimeout = 30000;
        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        boolean isSslVerify = false;
        SSLSocketFactory sslSocketFactory = null;
        X509TrustManager trustManager = null;

        if (request instanceof VolleyRequest) {
            connectTimeout = ((VolleyRequest) request).connectTimeoutMilliSecond();
            readTimeout = ((VolleyRequest) request).readTimeoutMilliSecond();
            writeTimeout = ((VolleyRequest) request).writeTimeoutMilliSecond();

            clientBuilder.retryOnConnectionFailure(((VolleyRequest) request).isRetryOnConnectionFailure());
            hostnameVerifier = ((VolleyRequest) request).getHostnameVerifier();

            isSslVerify = ((VolleyRequest) request).isSslVerify();
            if (isSslVerify) {
                sslSocketFactory = ((VolleyRequest) request).getSslSocketFactory();
                trustManager = ((VolleyRequest) request).getTrustManager();
            }
        }

        clientBuilder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS);
        clientBuilder.readTimeout(readTimeout, TimeUnit.MILLISECONDS);
        clientBuilder.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS);

        if (hostnameVerifier != null) {
            clientBuilder.hostnameVerifier(hostnameVerifier);
        }

        if (isSslVerify && sslSocketFactory != null && trustManager != null) {
            clientBuilder.sslSocketFactory(sslSocketFactory, trustManager);
        }

        OkHttpClient client = clientBuilder.build();
        okhttp3.Request.Builder okHttpBuilder = new okhttp3.Request.Builder();

        Map<String, String> header = request.getHeaders();
        for (String name : header.keySet()) {
            okHttpBuilder.addHeader(name, header.get(name));
        }

        for (String name : additionalHeaders.keySet()) {
            okHttpBuilder.addHeader(name, additionalHeaders.get(name));
        }

        setConnectionParametersForRequest(okHttpBuilder, request);

        okhttp3.Request okhttp3Request = okHttpBuilder.url(request.getUrl()).build();

        Response okHttpResponse = client.newCall(okhttp3Request).execute();

        StatusLine responseStatus = new BasicStatusLine
                (
                        parseProtocol(okHttpResponse.protocol()),
                        okHttpResponse.code(),
                        okHttpResponse.message()
                );


        InputStream content = okHttpResponse.body().byteStream();
        long contentLen = okHttpResponse.body().contentLength();

        Headers responseHeaders = okHttpResponse.headers();
        List<Header> headers = new ArrayList<>();
        for (int i = 0, len = responseHeaders.size(); i < len; i++) {
            final String name = responseHeaders.name(i), value = responseHeaders.value(i);
            if (name != null) {
                headers.add(new Header(name, value));
            }
        }
        HttpResponse response = new HttpResponse(responseStatus.getStatusCode(), headers, (int) contentLen, content);

        return response;
    }


    private static void setConnectionParametersForRequest
            (okhttp3.Request.Builder builder, Request<?> request)
            throws IOException, AuthFailureError {
        switch (request.getMethod()) {
            case Request.Method.DEPRECATED_GET_OR_POST:
                byte[] postBody = request.getPostBody();
                if (postBody != null) {
                    builder.post(RequestBody.create
                            (MediaType.parse(request.getPostBodyContentType()), postBody));
                }
                break;

            case Request.Method.GET:
                builder.get();
                break;

            case Request.Method.DELETE:
                builder.delete();
                break;

            case Request.Method.POST:
                RequestBody body = createRequestBody(request);
                builder.post(body);
                break;

            case Request.Method.PUT:
                builder.put(createRequestBody(request));
                break;

            case Request.Method.HEAD:
                builder.head();
                break;

            case Request.Method.OPTIONS:
                builder.method("OPTIONS", null);
                break;

            case Request.Method.TRACE:
                builder.method("TRACE", null);
                break;

            case Request.Method.PATCH:
                builder.patch(createRequestBody(request));
                break;

            default:
                throw new IllegalStateException("Unknown method type.");
        }
    }

    private static RequestBody createRequestBody(Request request) throws AuthFailureError {
        byte[] body = request.getBody();
        if (null == body) {
            if (request.getMethod() == Request.Method.POST) {
                body = "".getBytes();
            } else {
                return null;
            }
        }

        return RequestBody.create(MediaType.parse(request.getBodyContentType()), body);
    }

    private static ProtocolVersion parseProtocol(final Protocol protocol) {
        switch (protocol) {
            case HTTP_1_0:
                return new ProtocolVersion("HTTP", 1, 0);
            case HTTP_1_1:
                return new ProtocolVersion("HTTP", 1, 1);
            case SPDY_3:
                return new ProtocolVersion("SPDY", 3, 1);
            case HTTP_2:
                return new ProtocolVersion("HTTP", 2, 0);
        }

        throw new IllegalAccessError("Unkwown protocol");
    }
}
